/*
 * Copyright 2011 University of Minnesota
 */
package com.likeyichu.lenskit.demo;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.grouplens.lenskit.ItemRecommender;
import org.grouplens.lenskit.ItemScorer;
import org.grouplens.lenskit.RecommenderBuildException;
import org.grouplens.lenskit.baseline.BaselineScorer;
import org.grouplens.lenskit.baseline.ItemMeanRatingItemScorer;
import org.grouplens.lenskit.baseline.UserMeanBaseline;
import org.grouplens.lenskit.baseline.UserMeanItemScorer;
import org.grouplens.lenskit.core.LenskitConfiguration;
import org.grouplens.lenskit.core.LenskitRecommender;
import org.grouplens.lenskit.data.dao.EventDAO;
import org.grouplens.lenskit.data.dao.ItemNameDAO;
import org.grouplens.lenskit.data.dao.MapItemNameDAO;
import org.grouplens.lenskit.data.text.Formats;
import org.grouplens.lenskit.data.text.TextEventDAO;
import org.grouplens.lenskit.knn.item.ItemItemScorer;
import org.grouplens.lenskit.scored.ScoredId;
import org.grouplens.lenskit.transform.normalize.BaselineSubtractingUserVectorNormalizer;
import org.grouplens.lenskit.transform.normalize.UserVectorNormalizer;

/**
 * Demonstration app for LensKit. This application builds an item-item CF model
 * from a CSV file, then generates recommendations for a user.
 */
public class HelloLenskit {
	public static void main(String[] args) throws RuntimeException, IOException, RecommenderBuildException {
		new HelloLenskit().run();
	}

	// about 100,000 pieces
	private File inputFile = new File("data/ratings.csv");
	// about 9,000 pieces
	private File movieFile = new File("data/movies.csv");
	private List<Long> users = new ArrayList<>(Arrays.asList(1L));

	public void run() throws RuntimeException, IOException, RecommenderBuildException {
		// We first need to configure the data access.
		// We will use a simple delimited file; you can use something else like
		// a database (see JDBCRatingDAO).
		EventDAO dao = TextEventDAO
				.create(inputFile, Formats.movieLensLatest());
		ItemNameDAO names = MapItemNameDAO.fromCSVFile(movieFile);
		LenskitConfiguration config = new LenskitConfiguration();
		// Use item-item CF to score items
		config.bind(ItemScorer.class)
		      .to(ItemItemScorer.class);
		// let's use personalized mean rating as the baseline/fallback predictor.
		// 2-step process:
		// First, use the user mean rating as the baseline scorer
		config.bind(BaselineScorer.class, ItemScorer.class)
		      .to(UserMeanItemScorer.class);
		// Second, use the item mean rating as the base for user means
		config.bind(UserMeanBaseline.class, ItemScorer.class)
		      .to(ItemMeanRatingItemScorer.class);
		// and normalize ratings by baseline prior to computing similarities
		config.bind(UserVectorNormalizer.class)
		      .to(BaselineSubtractingUserVectorNormalizer.class);
		// Next: load the LensKit algorithm configuration
//		LenskitConfiguration config = ConfigHelpers.load(new File(
//				"etc/item-item.groovy"));
		// Add our data component to the configuration
		config.bind(EventDAO.class).to(dao);

		// There are more parameters, roles, and components that can be set. See
		// the
		// JavaDoc for each recommender algorithm for more information.

		// Now that we have a configuration, build a recommender engine from the
		// configuration
		// and data source. This will compute the similarity matrix and return a
		// recommender
		// engine that uses it.
//		LenskitRecommenderEngine engine = LenskitRecommenderEngine
//				.build(config);

		// Finally, get the recommender and use it.
		LenskitRecommender rec = LenskitRecommender.build(config);
		// we want to recommend items
		ItemRecommender itemRec = rec.getItemRecommender();
		// for users
		for (long user : users) {
			// get 10 recommendation for the user
			List<ScoredId> recs = itemRec.recommend(user, 10, null, null);
			System.out.format("Recommendations for user %d:\n", user);
			for (ScoredId item : recs){
				System.out.format("\t%d (%s): %.2f\n", item.getId(), names.getItemName(item.getId()), item.getScore());
			}
		}// for-user
	}
}
/*Recommendations for user 1:
	40870 (C.R.A.Z.Y. (2005)): 5.63
	670 (World of Apu, The (Apur Sansar) (1959)): 5.59
	666 (All Things Fair (Lust och fägring stor) (1995)): 5.58
	854 (Ballad of Narayama, The (Narayama Bushiko) (1958)): 5.57
	4384 (Lumumba (2000)): 5.57
	138 (Neon Bible, The (1995)): 5.56
	128 (Jupiter's Wife (1994)): 5.53
	1412 (Some Mother's Son (1996)): 5.53
	2607 (Get Real (1998)): 5.51
	26082 (Harakiri (Seppuku) (1962)): 5.50
Recommendations for user 2:
	3222 (Carmen (1984)): 6.70
	1669 (Tango Lesson, The (1997)): 6.10
	7820 (Virgin Spring, The (Jungfrukällan) (1960)): 6.04
	5968 (Miami Blues (1990)): 5.98
	90524 (Abduction (2011)): 5.96
	3127 (Holy Smoke (1999)): 5.94
	3881 (Phish: Bittersweet Motel (2000)): 5.94
	5221 (Harrison's Flowers (2000)): 5.83
	25763 (Pandora's Box (Büchse der Pandora, Die) (1929)): 5.73
	2388 (Steam: The Turkish Bath (Hamam) (1997)): 5.73
*/
